<!DOCTYPE html>
<html lang="en-us">
  <head>

    <meta http-equiv="content-type" content="text/html; charset=utf-8">
    
<meta charset="UTF-8">
<title>Getting consistent scoring | Elasticsearch Guide [7.7] | Elastic</title>
<link rel="home" href="index.html" title="Elasticsearch Guide [7.7]">
<link rel="up" href="recipes.html" title="Recipes">
<link rel="prev" href="mixing-exact-search-with-stemming.html" title="Mixing exact search with stemming">
<link rel="next" href="static-scoring-signals.html" title="Incorporating static relevance signals into the score">
<meta name="DC.type" content="Learn/Docs/Elasticsearch/Reference/7.7">
<meta name="DC.subject" content="Elasticsearch">
<meta name="DC.identifier" content="7.7">
<meta name="robots" content="noindex,nofollow">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script src="https://cdn.optimizely.com/js/18132920325.js"></script>
    <link rel="apple-touch-icon" sizes="57x57" href="/apple-icon-57x57.png">
    <link rel="apple-touch-icon" sizes="60x60" href="/apple-icon-60x60.png">
    <link rel="apple-touch-icon" sizes="72x72" href="/apple-icon-72x72.png">
    <link rel="apple-touch-icon" sizes="76x76" href="/apple-icon-76x76.png">
    <link rel="apple-touch-icon" sizes="114x114" href="/apple-icon-114x114.png">
    <link rel="apple-touch-icon" sizes="120x120" href="/apple-icon-120x120.png">
    <link rel="apple-touch-icon" sizes="144x144" href="/apple-icon-144x144.png">
    <link rel="apple-touch-icon" sizes="152x152" href="/apple-icon-152x152.png">
    <link rel="apple-touch-icon" sizes="180x180" href="/apple-icon-180x180.png">
    <link rel="icon" type="image/png" href="/favicon-32x32.png" sizes="32x32">
    <link rel="icon" type="image/png" href="/android-chrome-192x192.png" sizes="192x192">
    <link rel="icon" type="image/png" href="/favicon-96x96.png" sizes="96x96">
    <link rel="icon" type="image/png" href="/favicon-16x16.png" sizes="16x16">
    <link rel="manifest" href="/manifest.json">
    <meta name="apple-mobile-web-app-title" content="Elastic">
    <meta name="application-name" content="Elastic">
    <meta name="msapplication-TileColor" content="#ffffff">
    <meta name="msapplication-TileImage" content="/mstile-144x144.png">
    <meta name="theme-color" content="#ffffff">
    <meta name="naver-site-verification" content="936882c1853b701b3cef3721758d80535413dbfd">
    <meta name="yandex-verification" content="d8a47e95d0972434">
    <meta name="localized" content="true">
    <meta name="st:robots" content="follow,index">
    <meta property="og:image" content="https://www.elastic.co/static/images/elastic-logo-200.png">
    <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
    <link rel="icon" href="/favicon.ico" type="image/x-icon">
    <link rel="apple-touch-icon-precomposed" sizes="64x64" href="/favicon_64x64_16bit.png">
    <link rel="apple-touch-icon-precomposed" sizes="32x32" href="/favicon_32x32.png">
    <link rel="apple-touch-icon-precomposed" sizes="16x16" href="/favicon_16x16.png">
    <!-- Give IE8 a fighting chance -->
    <!--[if lt IE 9]>
    <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
    <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
    <![endif]-->
    <link rel="stylesheet" type="text/css" href="/guide/static/styles.css">
  </head>

  <!--© 2015-2021 Elasticsearch B.V. Copying, publishing and/or distributing without written permission is strictly prohibited.-->

  <body>
    <!-- Google Tag Manager -->
    <script>dataLayer = [];</script><noscript><iframe src="//www.googletagmanager.com/ns.html?id=GTM-58RLH5" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
    <script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= '//www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); })(window,document,'script','dataLayer','GTM-58RLH5');</script>
    <!-- End Google Tag Manager -->

    <!-- Global site tag (gtag.js) - Google Analytics -->
    <script async src="https://www.googletagmanager.com/gtag/js?id=UA-12395217-16"></script>
    <script>
      window.dataLayer = window.dataLayer || [];
      function gtag(){dataLayer.push(arguments);}
      gtag('js', new Date());
      gtag('config', 'UA-12395217-16');
    </script>

    <!--BEGIN QUALTRICS WEBSITE FEEDBACK SNIPPET-->
    <script type="text/javascript">
      (function(){var g=function(e,h,f,g){
      this.get=function(a){for(var a=a+"=",c=document.cookie.split(";"),b=0,e=c.length;b<e;b++){for(var d=c[b];" "==d.charAt(0);)d=d.substring(1,d.length);if(0==d.indexOf(a))return d.substring(a.length,d.length)}return null};
      this.set=function(a,c){var b="",b=new Date;b.setTime(b.getTime()+6048E5);b="; expires="+b.toGMTString();document.cookie=a+"="+c+b+"; path=/; "};
      this.check=function(){var a=this.get(f);if(a)a=a.split(":");else if(100!=e)"v"==h&&(e=Math.random()>=e/100?0:100),a=[h,e,0],this.set(f,a.join(":"));else return!0;var c=a[1];if(100==c)return!0;switch(a[0]){case "v":return!1;case "r":return c=a[2]%Math.floor(100/c),a[2]++,this.set(f,a.join(":")),!c}return!0};
      this.go=function(){if(this.check()){var a=document.createElement("script");a.type="text/javascript";a.src=g;document.body&&document.body.appendChild(a)}};
      this.start=function(){var a=this;window.addEventListener?window.addEventListener("load",function(){a.go()},!1):window.attachEvent&&window.attachEvent("onload",function(){a.go()})}};
      try{(new g(100,"r","QSI_S_ZN_emkP0oSe9Qrn7kF","https://znemkp0ose9qrn7kf-elastic.siteintercept.qualtrics.com/WRSiteInterceptEngine/?Q_ZID=ZN_emkP0oSe9Qrn7kF")).start()}catch(i){}})();
    </script><div id="ZN_emkP0oSe9Qrn7kF"><!--DO NOT REMOVE-CONTENTS PLACED HERE--></div>
    <!--END WEBSITE FEEDBACK SNIPPET-->

    <div id="elastic-nav" style="display:none;"></div>
    <script src="https://www.elastic.co/elastic-nav.js"></script>

    <!-- Subnav -->
    <div>
      <div>
        <div class="tertiary-nav d-none d-md-block">
          <div class="container">
            <div class="p-t-b-15 d-flex justify-content-between nav-container">
              <div class="breadcrum-wrapper"><span><a href="/guide/" style="font-size: 14px; font-weight: 600; color: #000;">Docs</a></span></div>
            </div>
          </div>
        </div>
      </div>
    </div>

    <div class="main-container">
      <section id="content">
        <div class="content-wrapper">

          <section id="guide" lang="en">
            <div class="container">
              <div class="row">
                <div class="col-xs-12 col-sm-8 col-md-8 guide-section">
                  <!-- start body -->
                  <div class="page_header">
<strong>IMPORTANT</strong>: No additional bug fixes or documentation updates
will be released for this version. For the latest information, see the
<a href="../current/index.html">current release documentation</a>.
</div>
<div id="content">
<div class="breadcrumbs">
<span class="breadcrumb-link"><a href="index.html">Elasticsearch Guide [7.7]</a></span>
»
<span class="breadcrumb-link"><a href="how-to.html">How To</a></span>
»
<span class="breadcrumb-link"><a href="recipes.html">Recipes</a></span>
»
<span class="breadcrumb-node">Getting consistent scoring</span>
</div>
<div class="navheader">
<span class="prev">
<a href="mixing-exact-search-with-stemming.html">« Mixing exact search with stemming</a>
</span>
<span class="next">
<a href="static-scoring-signals.html">Incorporating static relevance signals into the score »</a>
</span>
</div>
<div class="section">
<div class="titlepage"><div><div>
<h2 class="title">
<a id="consistent-scoring"></a>Getting consistent scoring<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elastic/elasticsearch/edit/7.7/docs/reference/how-to/recipes/scoring.asciidoc">edit</a>
</h2>
</div></div></div>
<p>The fact that Elasticsearch operates with shards and replicas adds challenges
when it comes to having good scoring.</p>
<h4>
<a id="_scores_are_not_reproducible"></a>Scores are not reproducible<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elastic/elasticsearch/edit/7.7/docs/reference/how-to/recipes/scoring.asciidoc">edit</a>
</h4>
<p>Say the same user runs the same request twice in a row and documents do not come
back in the same order both times, this is a pretty bad experience isn’t it?
Unfortunately this is something that can happen if you have replicas
(<code class="literal">index.number_of_replicas</code> is greater than 0). The reason is that Elasticsearch
selects the shards that the query should go to in a round-robin fashion, so it
is quite likely if you run the same query twice in a row that it will go to
different copies of the same shard.</p>
<p>Now why is it a problem? Index statistics are an important part of the score.
And these index statistics may be different across copies of the same shard
due to deleted documents. As you may know when documents are deleted or updated,
the old document is not immediately removed from the index, it is just marked
as deleted and it will only be removed from disk on the next time that the
segment this old document belongs to is merged. However for practical reasons,
those deleted documents are taken into account for index statistics. So imagine
that the primary shard just finished a large merge that removed lots of deleted
documents, then it might have index statistics that are sufficiently different
from the replica (which still have plenty of deleted documents) so that scores
are different too.</p>
<p>The recommended way to work around this issue is to use a string that identifies
the user that is logged is (a user id or session id for instance) as a
<a class="xref" href="search-request-body.html#request-body-search-preference" title="Preference">preference</a>. This ensures that all queries of a
given user are always going to hit the same shards, so scores remain more
consistent across queries.</p>
<p>This work around has another benefit: when two documents have the same score,
they will be sorted by their internal Lucene doc id (which is unrelated to the
<code class="literal">_id</code>) by default. However these doc ids could be different across copies of
the same shard. So by always hitting the same shard, we would get more
consistent ordering of documents that have the same scores.</p>
<h4>
<a id="_relevancy_looks_wrong"></a>Relevancy looks wrong<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elastic/elasticsearch/edit/7.7/docs/reference/how-to/recipes/scoring.asciidoc">edit</a>
</h4>
<p>If you notice that two documents with the same content get different scores or
that an exact match is not ranked first, then the issue might be related to
sharding. By default, Elasticsearch makes each shard responsible for producing
its own scores. However since index statistics are an important contributor to
the scores, this only works well if shards have similar index statistics. The
assumption is that since documents are routed evenly to shards by default, then
index statistics should be very similar and scoring would work as expected.
However in the event that you either:</p>
<div class="ulist itemizedlist">
<ul class="itemizedlist">
<li class="listitem">
use routing at index time,
</li>
<li class="listitem">
query multiple <em>indices</em>,
</li>
<li class="listitem">
or have too little data in your index
</li>
</ul>
</div>
<p>then there are good chances that all shards that are involved in the search
request do not have similar index statistics and relevancy could be bad.</p>
<p>If you have a small dataset, the easiest way to work around this issue is to
index everything into an index that has a single shard
(<code class="literal">index.number_of_shards: 1</code>), which is the default. Then index statistics
will be the same for all documents and scores will be consistent.</p>
<p>Otherwise the recommended way to work around this issue is to use the
<a class="xref" href="search-request-body.html#dfs-query-then-fetch" title="Dfs, Query Then Fetch"><code class="literal">dfs_query_then_fetch</code></a> search type. This will make
Elasticsearch perform an initial round trip to all involved shards, asking
them for their index statistics relatively to the query, then the coordinating
node will merge those statistics and send the merged statistics alongside the
request when asking shards to perform the <code class="literal">query</code> phase, so that shards can
use these global statistics rather than their own statistics in order to do the
scoring.</p>
<p>In most cases, this additional round trip should be very cheap. However in the
event that your query contains a very large number of fields/terms or fuzzy
queries, beware that gathering statistics alone might not be cheap since all
terms have to be looked up in the terms dictionaries in order to look up
statistics.</p>
</div>
<div class="navfooter">
<span class="prev">
<a href="mixing-exact-search-with-stemming.html">« Mixing exact search with stemming</a>
</span>
<span class="next">
<a href="static-scoring-signals.html">Incorporating static relevance signals into the score »</a>
</span>
</div>
</div>

                  <!-- end body -->
                </div>
                <div class="col-xs-12 col-sm-4 col-md-4" id="right_col">
                  <div id="rtpcontainer" style="display: block;">
                    <div class="mktg-promo">
                      <h3>Most Popular</h3>
                      <ul class="icons">
                        <li class="icon-elasticsearch-white"><a href="https://www.elastic.co/webinars/getting-started-elasticsearch?baymax=default&amp;elektra=docs&amp;storm=top-video">Get Started with Elasticsearch: Video</a></li>
                        <li class="icon-kibana-white"><a href="https://www.elastic.co/webinars/getting-started-kibana?baymax=default&amp;elektra=docs&amp;storm=top-video">Intro to Kibana: Video</a></li>
                        <li class="icon-logstash-white"><a href="https://www.elastic.co/webinars/introduction-elk-stack?baymax=default&amp;elektra=docs&amp;storm=top-video">ELK for Logs &amp; Metrics: Video</a></li>
                      </ul>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </section>

        </div>


<div id="elastic-footer"></div>
<script src="https://www.elastic.co/elastic-footer.js"></script>
<!-- Footer Section end-->

      </section>
    </div>

<script src="/guide/static/jquery.js"></script>
<script type="text/javascript" src="/guide/static/docs.js"></script>
<script type="text/javascript">
  window.initial_state = {}</script>
  </body>
</html>
